#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <cstring>
#include <cstdio>
#include <unistd.h>
#include <cstdlib>
#include<yaml-cpp/yaml.h>
#include<yaml-cpp/yaml.h>

using namespace std;

#include "TApplication.h"
#include "TFile.h"
#include "TTree.h"
#include "TRandom3.h"

#include "setup.h"

void Sort2Coin_ToF()
{
	int i = 0, j = 0, k = 0, m = 0, n = 0, p = 0;

	clock_t start, finish;

	string strRead;
	// ifstream fileName("../config/ListRuns_ToF.txt");
	for(auto sRun_ToF:finalFileName)
	{
			start = clock();

			// sSort = "../RootData/ToF_" + sRun_ToF + ".root";
			// sCoin = "../RootData/ToF_Sort_Coin_" + sRun_ToF + ".root";
			string sSort = "../RootData/ToF_Sort_" + sRun_ToF + ".root";
			string sCoin = "../RootData/ToF_Sort_Coin_" + sRun_ToF + ".root";

			printf("\n**********Now converting %s to %s!**********\n\n", sSort.c_str(), sCoin.c_str());

			TFile *fSort = new TFile(sSort.c_str());
			if (fSort->IsZombie())
			{
				cout << "Error in opening " << sSort << "!\n";
				delete fSort;
				continue;
			}
			TTree *treeSort_ToF;
			fSort->GetObject("treeSort_ToF", treeSort_ToF);
			if (!treeSort_ToF)
			{
				cout << "Error read the tree of treeSort_ToF!\n";
				continue;
			}
			long long tsSlcSort_ToF = 0;
			vector<double> *coarse_ToF=nullptr;
			vector<double> *tmStpSort_ToF=nullptr;
			vector<double>*shift_ToF=nullptr;
			vector<short>*brd_ToF=nullptr;
			vector<short>*ch_ToF=nullptr;
			vector<short>*fine_ToF=nullptr;
			
			
			int nSig_ToF = 0;
			// short brd_ToF[MaxSig_ToF] = {0}, ch_ToF[MaxSig_ToF] = {0}, shift_ToF[MaxSig_ToF] = {0}, fine_ToF[MaxSig_ToF] = {0};
			treeSort_ToF->SetBranchAddress("tsSlcSort_ToF", &tsSlcSort_ToF);
			treeSort_ToF->SetBranchAddress("nSig_ToF", &nSig_ToF);
			treeSort_ToF->SetBranchAddress("brd_ToF", &brd_ToF);
			treeSort_ToF->SetBranchAddress("ch_ToF", &ch_ToF);
			treeSort_ToF->SetBranchAddress("tmStpSort_ToF", &tmStpSort_ToF);
			treeSort_ToF->SetBranchAddress("shift_ToF", &shift_ToF);
			treeSort_ToF->SetBranchAddress("coarse_ToF", &coarse_ToF);
			treeSort_ToF->SetBranchAddress("fine_ToF", &fine_ToF);

			TFile *fCoin = new TFile(sCoin.c_str(), "RECREATE");
			TTree *treeCoin_ToF = new TTree("treeCoin_ToF", "tree of coincident ToF data");
			long long tsSlc0_ToF = 0,  tsSlc_ToF[NBD_ToF][NCH_ToF][NMaxHit_ToF] = {0};
			double tmStp0_ToF=0, tmStp_ToF[NBD_ToF][NCH_ToF][NMaxHit_ToF] = {0}, tmCrs_ToF[NBD_ToF][NCH_ToF][NMaxHit_ToF] = {0};
			short nCoin_ToF = 0, nHit_ToF[NBD_ToF][NCH_ToF] = {0}, tsFine_ToF[NBD_ToF][NCH_ToF][NMaxHit_ToF] = {0};
			treeCoin_ToF->Branch("sRun_ToF", &sRun_ToF);
			treeCoin_ToF->Branch("tsSlc0_ToF", &tsSlc0_ToF, "tsSlc0_ToF/L");
			treeCoin_ToF->Branch("tmStp0_ToF", &tmStp0_ToF, "tmStp0_ToF/D");
			treeCoin_ToF->Branch("nCoin_ToF", &nCoin_ToF, "nCoin_ToF/S");
			treeCoin_ToF->Branch("nHit_ToF", nHit_ToF, ("nHit_ToF[" + to_string(NBD_ToF) + "][" + to_string(NCH_ToF) + "]/S").c_str());
			treeCoin_ToF->Branch("tsSlc_ToF", tsSlc_ToF, ("tsSlc_ToF[" + to_string(NBD_ToF) + "][" + to_string(NCH_ToF) + "][" + to_string(NMaxHit_ToF) + "]/L").c_str());
			treeCoin_ToF->Branch("tmStp_ToF", tmStp_ToF, ("tmStp_ToF[" + to_string(NBD_ToF) + "][" + to_string(NCH_ToF) + "][" + to_string(NMaxHit_ToF) + "]/D").c_str());
			treeCoin_ToF->Branch("tmCrs_ToF", tmCrs_ToF, ("tmCrs_ToF[" + to_string(NBD_ToF) + "][" + to_string(NCH_ToF) + "][" + to_string(NMaxHit_ToF) + "]/D").c_str());
			treeCoin_ToF->Branch("tsFine_ToF", tsFine_ToF, ("tsFine_ToF[" + to_string(NBD_ToF) + "][" + to_string(NCH_ToF) + "][" + to_string(NMaxHit_ToF) + "]/S").c_str());

			treeSort_ToF->GetEntry(0);
			tsSlc0_ToF = tsSlcSort_ToF;
			tmStp0_ToF = (*tmStpSort_ToF)[0];

			long long tsDiff = 0;
			long long iEnt = 0, nEnt = treeSort_ToF->GetEntries();
			p = 0;
			int iBd = 0, iCh = 0, iSig = 0;
			for (iEnt = 0; iEnt < nEnt; iEnt++)
			{
				treeSort_ToF->GetEntry(iEnt);

				for (iSig = 0; iSig < nSig_ToF; iSig++)
				{
					tsDiff = (tsSlcSort_ToF - tsSlc0_ToF) * 102400 + ((*tmStpSort_ToF)[iSig] - tmStp0_ToF);
					iBd = (*brd_ToF)[iSig];
					// iBd = brd_ToF[iSig] - 1;
					iCh = (*ch_ToF)[iSig];
					if (tsDiff <= WidCoin_ToF && nHit_ToF[iBd][iCh] < NMaxHit_ToF)
					{
						k = nHit_ToF[iBd][iCh];
						tsSlc_ToF[iBd][iCh][k] = tsSlcSort_ToF;
						tmStp_ToF[iBd][iCh][k] = (*tmStpSort_ToF)[iSig];
						if(UseCoarse)
							tmCrs_ToF[iBd][iCh][k] = (*coarse_ToF)[iSig]*TimeCrs_ToF;
						else
							tmCrs_ToF[iBd][iCh][k] = TimeSft_ToF * (*shift_ToF)[iSig];
						tsFine_ToF[iBd][iCh][k] = (*fine_ToF)[iSig];
						nHit_ToF[iBd][iCh]++;
						nCoin_ToF++;
					}
					if (nCoin_ToF > 0 && (tsDiff > WidCoin_ToF || (iSig == nSig_ToF - 1 && iEnt == nEnt - 1)))
					{
						treeCoin_ToF->Fill();

						tsSlc0_ToF = tsSlcSort_ToF;
						tmStp0_ToF = (*tmStpSort_ToF)[iSig];
						nCoin_ToF = 0;
						memset(nHit_ToF, 0, sizeof(nHit_ToF));
						memset(tsSlc_ToF, 0, sizeof(tsSlc_ToF));
						memset(tmStp_ToF, 0, sizeof(tmStp_ToF));
						memset(tmCrs_ToF, 0, sizeof(tmCrs_ToF));
						memset(tsFine_ToF, 0, sizeof(tsFine_ToF));

						if (!(iSig == nSig_ToF - 1 && iEnt == nEnt - 1))
							iSig--;
					}
				}
				if ((10.0 * iEnt / nEnt) >= p)
				{
					printf("**********%d%% of %lld events of Run#%s have been processed**********\n", 10 * p, nEnt, sRun_ToF.c_str());
					p++;
				}
			}
			fCoin->cd();
			treeCoin_ToF->Write("", TObject::kOverwrite);

			fCoin->Close();
			fSort->Close();
			delete fSort;
			delete fCoin;

			finish = clock();
			cout << "\nTime for processing Run#" << sRun_ToF << " is: " << double(finish - start) / CLOCKS_PER_SEC << " s\n\n";
		}
		
		
	}


#ifndef __CINT__
int main(int argc, char **argv)
{
	Sort2Coin_ToF();
	return 0;
}
#endif
